package it.uniroma2.art.coda.extension;

import it.uniroma2.art.coda.exception.FelixInitializationException;
import it.uniroma2.art.coda.interfaces.IdentityResolverInterface;
import it.uniroma2.art.coda.interfaces.ProjectionRulesDeciderInterface;
import it.uniroma2.art.coda.interfaces.ResourcesSmartSuggesterInterface;
import it.uniroma2.art.coda.interfaces.TriplesSmartSuggesterInterface;
import it.uniroma2.art.coda.projectionrule.ParserPR;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author Andrea Turbati
 */

public class CODAOSGiManger extends ARTOSGiManager {

	private static CODAOSGiManger manager = null;
	protected static Log logger = LogFactory.getLog(CODAOSGiManger.class);

	private static final String projRuleParserPath = "ProjRuleParser";

	private static final String prjDisPath = "PrjRulDec";
	private static final String idResPath = "IdRes";
	private static final String resSmartSuggPath = "ResSmartSugg";
	private static final String triSmartSuggPath = "TriSmartSugg";
	

	private static String filePropertyName = "osgi.properties";
	private static String propertyName = "art.coda.osgi.packages";

	protected CODAOSGiManger(File felixDir) throws FelixInitializationException {
		super(felixDir, filePropertyName, propertyName);
	}

	/**
	 * Method to inialize the OSGi framwork using felix implementation
	 * 
	 * @param oSGiDir
	 *            the directory where the bundle will be stored
	 * @return the CODAOSGiManger
	 * @throws FelixInitializationException
	 */
	public static CODAOSGiManger initialize(File oSGiDir) throws FelixInitializationException {
		manager = new CODAOSGiManger(oSGiDir);
		return manager;
	}

	/**
	 * Get the CODAOSGiManger
	 * 
	 * @return the CODAOSGiManger
	 */
	public static CODAOSGiManger getManager() {
		return manager;
	}

	/**
	 * Stop Felix
	 */
	public void stop() {
		stopFelix();
	}

	/**
	 * Search, load and install all the bundles regarding the Projection Rules Parser Annotation module
	 * 
	 * @param rootDir
	 *            the directory where to start looking for all the bundles regarding Projection Rule Parser
	 * @param subDirPresent
	 *            true if there are subdirectories in the rootDirectory, false otherwise
	 */
	public void loadProjectionRulesParser(String rootDir, boolean subDirPresent) {
		bundleToBeStarted.clear();
		if (subDirPresent) {
			File[] subDirs = (new File(rootDir)).listFiles();
			if (subDirs == null)
				return;
			for (File subDir : subDirs) {
				File[] resourceDirs = (new File(subDir, projRuleParserPath)).listFiles();
				if (resourceDirs == null)
					return;
				for (File resourceDir : resourceDirs) {
					findAndInstallPlugin(resourceDir);
				}
			}
		} else {
			File[] resourceDirs = (new File(rootDir, projRuleParserPath).listFiles());
			if (resourceDirs == null)
				return;
			for (File resourceDir : resourceDirs) {
				findAndInstallPlugin(resourceDir);
			}
		}
		// Start all the bundle just found
		startAllBundle();
	}

	/**
	 * Search, load and install all the bundles regarding the Projection Rules Decider module
	 * 
	 * @param rootDir
	 *            the directory where to start looking for all the bundles regarding the Projection
	 *            Disambiguation Annotation
	 * @param subDirPresent
	 *            true if there are subdirectories in the rootDirectory, false otherwise
	 * 
	 */
	public void loadProjectionRulesDecider(String rootDir, boolean subDirPresent) {
		bundleToBeStarted.clear();
		if (subDirPresent) {
			File[] subDirs = (new File(rootDir)).listFiles();
			if (subDirs == null)
				return;
			for (File subDir : subDirs) {
				File[] resourceDirs = (new File(subDir, prjDisPath)).listFiles();
				if (resourceDirs == null)
					continue;
				for (File resourceDir : resourceDirs) {
					findAndInstallPlugin(resourceDir);
				}
			}
		} else {
			File[] resourceDirs = (new File(rootDir, prjDisPath).listFiles());
			if (resourceDirs == null)
				return;
			for (File resourceDir : resourceDirs) {
				findAndInstallPlugin(resourceDir);
			}
		}
		// Start all the bundle just found
		startAllBundle();
	}

	/**
	 * Search, load and install all the bundles regarding the Identity Resolver module
	 * 
	 * @param rootDir
	 *            the directory where to start looking for all the bundles regarding the Identity Resolution
	 *            Annotation
	 * @param subDirPresent
	 *            true if there are subdirectories in the rootDirectory, false otherwise
	 * 
	 */
	public void loadIdentityResolver(String rootDir, boolean subDirPresent) {
		bundleToBeStarted.clear();
		if (subDirPresent) {
			File[] subDirs = (new File(rootDir)).listFiles();
			if (subDirs == null)
				return;
			for (File subDir : subDirs) {
				File[] resourceDirs = (new File(subDir, idResPath)).listFiles();
				if (resourceDirs == null)
					return;
				for (File resourceDir : resourceDirs) {
					findAndInstallPlugin(resourceDir);
				}
			}
		} else {
			File[] resourceDirs = (new File(rootDir, idResPath).listFiles());
			if (resourceDirs == null)
				return;
			for (File resourceDir : resourceDirs) {
				findAndInstallPlugin(resourceDir);
			}
		}
		// Start all the bundle just found
		startAllBundle();
	}

	/**
	 * This method search, load and install all the bundles regarding the Resources Smart Suggestion module
	 * 
	 * @param rootDir
	 *            the directory where to start looking for all the bundles regarding the Resouces Smart Suggestion
	 * @param subDirPresent
	 *            true if there are subdirectories in the rootDirectory, false otherwise
	 * 
	 */
	public void loadResourcesSmartSuggestion(String rootDir, boolean subDirPresent) {
		bundleToBeStarted.clear();
		if (subDirPresent) {
			File[] subDirs = (new File(rootDir)).listFiles();
			if (subDirs == null)
				return;
			for (File subDir : subDirs) {
				File[] resourceDirs = (new File(subDir, resSmartSuggPath)).listFiles();
				if (resourceDirs == null)
					continue;
				for (File resourceDir : resourceDirs) {
					findAndInstallPlugin(resourceDir);
				}
			}
		} else {
			File[] resourceDirs = (new File(rootDir, resSmartSuggPath).listFiles());
			if (resourceDirs == null)
				return;
			for (File resourceDir : resourceDirs) {
				findAndInstallPlugin(resourceDir);
			}
		}
		// Start all the bundle just found
		startAllBundle();
	}
	
	/**
	 * This method search, load and install all the bundles regarding the Triples Smart Suggestion module
	 * 
	 * @param rootDir
	 *            the directory where to start looking for all the bundles regarding the Smart Suggestion
	 * @param subDirPresent
	 *            true if there are subdirectories in the rootDirectory, false otherwise
	 * 
	 */
	public void loadTriplesSmartSuggestion(String rootDir, boolean subDirPresent) {
		bundleToBeStarted.clear();
		if (subDirPresent) {
			File[] subDirs = (new File(rootDir)).listFiles();
			if (subDirs == null)
				return;
			for (File subDir : subDirs) {
				File[] resourceDirs = (new File(subDir, triSmartSuggPath)).listFiles();
				if (resourceDirs == null)
					continue;
				for (File resourceDir : resourceDirs) {
					findAndInstallPlugin(resourceDir);
				}
			}
		} else {
			File[] resourceDirs = (new File(rootDir, triSmartSuggPath).listFiles());
			if (resourceDirs == null)
				return;
			for (File resourceDir : resourceDirs) {
				findAndInstallPlugin(resourceDir);
			}
		}
		// Start all the bundle just found
		startAllBundle();
	}

	/**
	 * Get the map containing all the implementation of the Projection Rule Parser loaded by Felix
	 * 
	 * @return the map containing all the implementation of the Projection Rule Parser
	 */
	public HashMap<String, ParserPR> getProjectionRuleParserMap() {
		HashMap<String, ParserPR> projectionRuleParserMap = new HashMap<String, ParserPR>();

		ArrayList<ParserPR> prpList = getServletExtensionsForType(ParserPR.class);

		for (ParserPR projRuleParse : prpList) {
			projectionRuleParserMap.put(projRuleParse.getId(), projRuleParse);
		}
		return projectionRuleParserMap;
	}

	/**
	 * Get the map containing all the implementation of the Projection Disambiguation Annotation loaded by
	 * Felix
	 * 
	 * @return the map containing all the implementation of the Projection Disambiguation Annotation
	 */
	public HashMap<String, ProjectionRulesDeciderInterface> getProjectonRulesDeciderMap() {
		HashMap<String, ProjectionRulesDeciderInterface> projectionDisambiguatioAnnotationnMap = new HashMap<String, ProjectionRulesDeciderInterface>();

		ArrayList<ProjectionRulesDeciderInterface> pdaList = getServletExtensionsForType(ProjectionRulesDeciderInterface.class);

		for (ProjectionRulesDeciderInterface projectionDisambiguation : pdaList) {
			projectionDisambiguatioAnnotationnMap.put(projectionDisambiguation.getId(),
					projectionDisambiguation);
		}
		return projectionDisambiguatioAnnotationnMap;
	}

	/**
	 * Get the map containing all the implementation of the Identity Resolution Annotation loaded by Felix
	 * 
	 * @return the map containing all the implementation of the Identity Resolution Annotation
	 */
	public HashMap<String, IdentityResolverInterface> getIdentityResolutionMap() {
		HashMap<String, IdentityResolverInterface> identityResolutionAnnotationMap = new HashMap<String, IdentityResolverInterface>();

		ArrayList<IdentityResolverInterface> irList = getServletExtensionsForType(IdentityResolverInterface.class);

		for (IdentityResolverInterface identityResolutionAnnotation : irList) {
			identityResolutionAnnotationMap.put(identityResolutionAnnotation.getId(),
					identityResolutionAnnotation);
		}
		return identityResolutionAnnotationMap;
	}

	/**
	 * Get the map containing all the implementation of the Smart Suggestion Resources loaded by Felix
	 * 
	 * @return the map containing all the implementation of the Smart Suggestion Resources
	 */
	public HashMap<String, ResourcesSmartSuggesterInterface> getResourcesSmartSuggestionMap() {
		HashMap<String, ResourcesSmartSuggesterInterface> resSmartSuggestionResMap = new HashMap<String, ResourcesSmartSuggesterInterface>();

		ArrayList<ResourcesSmartSuggesterInterface> rssList = getServletExtensionsForType(ResourcesSmartSuggesterInterface.class);

		for (ResourcesSmartSuggesterInterface smartSuggestion : rssList) {
			resSmartSuggestionResMap.put(smartSuggestion.getId(), smartSuggestion);
		}
		return resSmartSuggestionResMap;
	}
	
	/**
	 * Get the map containing all the implementation of the Smart Suggestion Triple loaded by Felix
	 * 
	 * @return the map containing all the implementation of the Smart Suggestion Triple
	 */
	public HashMap<String, TriplesSmartSuggesterInterface> getSmartSuggestionTripleMap() {
		HashMap<String, TriplesSmartSuggesterInterface> triplesSmartSuggestionTriMap = new HashMap<String, TriplesSmartSuggesterInterface>();

		ArrayList<TriplesSmartSuggesterInterface> tssList = getServletExtensionsForType(TriplesSmartSuggesterInterface.class);

		for (TriplesSmartSuggesterInterface smartSuggestion : tssList) {
			triplesSmartSuggestionTriMap.put(smartSuggestion.getId(), smartSuggestion);
		}
		return triplesSmartSuggestionTriMap;
	}
}
